/*
 * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 *
 * This file is part of Harmattan SmashMiner OpenGL game application.
 * 
 * Harmattan SmashMiner OpenGL Example Application version 1.0.0
 *  
 * Latest update: 15.4.2011
 *
 * The Harmattan SmashMiner OpenGL example application demonstrates how to use 
 * the OpenGL ES in Harmattan devices.
 *
 * This example is provided as a starting point for 3rd party
 * developers (you) to ease the implementation of OpenGL based 
 * games. Ideas, parts of code or methodologies that this
 * example application uses can be freely used without restrictions.
 *
 * See file README.txt how to build and compile this example application
 * in the Harmattan SDK environment. 
 * 
 * See file INSTALL.txt to find out what is required to run this
 * application and how to install the application to the device or
 * alternatively in QEMU-emulator.
 *
 * The LICENSE.txt file explains the license this software is provided
 * with. A copy of the same license is included in this source file.
 * 
 */

/*
 * Copyright (C) 2011 by Nokia Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/** \file gamewidget_graphics.cpp
 * This file is part of \c GameWidget class. 
 * Initializing OpenGL graphics objects are defined in this file.
 */

#include "gamewidget.h"
#include "gameengine.h"
#include "math.h"
#include "ufo.h"
#include <QDebug>

#include <QDebug>


/// Initiates spaceship vertex, normal and light data.
void GameWidget::initSpaceShip()
{
    GLfloat *v_cone = spaceshipConeVertexData;
    GLfloat *n_cone = spaceshipConeNormalData;
    GLfloat *v_ball = spaceshipBallVertexData;
    GLfloat *n_ball = spaceshipBallNormalData;

    spaceshipConeColorData[0] = 0.60f;	//old=0.5f
    spaceshipConeColorData[1] = 1.00f;	//old=0.5f
    spaceshipConeColorData[2] = 0.60f;	//old=1.0f
    spaceshipConeColorData[3] = 1.0f;

    spaceshipBallColorData[0] = 0.95f;	//old=1.0f;
    spaceshipBallColorData[1] = 0.95f;	//old=1.0f;
    spaceshipBallColorData[2] = 0.95f;	//old=0.0f;
    spaceshipBallColorData[3] = 1.0f;

#ifdef SMASHMINER_CONFIG_USE_OPENGL_ES_2

    GLes2MakeLightMaterialData(lightAmbient, spaceshipConeColorData, spaceshipConeAmbientLmData);
    GLes2MakeLightMaterialData(lightDiffuse, spaceshipConeColorData, spaceshipConeDiffuseLmData);
    GLes2MakeLightMaterialData(lightAmbient, spaceshipBallColorData, spaceshipBallAmbientLmData);
    GLes2MakeLightMaterialData(lightDiffuse, spaceshipBallColorData, spaceshipBallDiffuseLmData);

#endif  // SMASHMINER_CONFIG_USE_OPENGL_ES_2

    GLfloat scale = GameEngine::GameObjectRadiusSpaceCraft;

    GLfloat wngWdt = 0.3f * scale;
    GLfloat wngLgt = 1.0f * scale;

    GLfloat conEdZ = +0.3f * scale;
    GLfloat conCeZ = +0.0f * scale;

    GLfloat centeX = +0.0f;
    GLfloat centeY = +0.0f;

    // Cone mode points
    //                
    //                A0
    //          A1 ------- A2
    //                |
    //                |
    //                |
    //                |
    // D2             |            B1
    //   |            | Ce        |
    // D0|------------X-----------| B0
    //   |            |           |
    // D1             |            B2
    //                |
    //                |
    //                |
    //          C2 ------- C1
    //                C0
    //

    // Cone center coordinates
    conCe[x] = centeX;
    conCe[y] = centeY;
    conCe[z] = conCeZ;

    conA0[x] = centeX;
    conA0[y] = wngLgt;
    conA0[z] = conEdZ;

    conB0[x] = wngLgt;
    conB0[y] = centeY;
    conB0[z] = conEdZ;

    conC0[x] = centeX;
    conC0[y] = -wngLgt;
    conC0[z] = conEdZ;

    conD0[x] = -wngLgt;
    conD0[y] = centeY;
    conD0[z] = conEdZ;

    conA1[x] = -wngWdt;
    conA1[y] = wngLgt;
    conA1[z] = conCeZ;

    conA2[x] = wngWdt;
    conA2[y] = wngLgt;
    conA2[z] = conCeZ;

    conB1[x] = wngLgt;
    conB1[y] = wngWdt;
    conB1[z] = conCeZ;

    conB2[x] = wngLgt;
    conB2[y] = -wngWdt;
    conB2[z] = conCeZ;

    conC1[x] = wngWdt;
    conC1[y] = -wngLgt;
    conC1[z] = conCeZ;

    conC2[x] = -wngWdt;
    conC2[y] = -wngLgt;
    conC2[z] = conCeZ;

    conD1[x] = -wngLgt;
    conD1[y] = -wngWdt;
    conD1[z] = conCeZ;

    conD2[x] = -wngLgt;
    conD2[y] = wngWdt;
    conD2[z] = conCeZ;

    // Cone wing corner (bottom) points

    /* Ship ball mode coordinate points:
    //
    //    B8_______ B1
    //     /       \
    //    /         \
    // B7/           \ B2
    //   |           |
    //   |     x BC  |    ---
    // B6|           | B3 _|_ballCB
    //   \           /   
    //    \         /
    //  B5 \_______/ B4
    //
    //         |-----|
    //          ballCA
    */

    GLfloat b_radius = scale * 0.5;
    GLfloat angle = 22.5 * M_PI / 180.0;

    GLfloat ballZ1 = +0.4f * scale;
    GLfloat ballZ2 = +0.0f * scale;

    balBC[x] = centeX; 
    balBC[y] = centeY; 
    balBC[z] = ballZ1;

    balB1[x] = sin(angle) * b_radius;
    balB1[y] = cos(angle) * b_radius;
    balB1[z] = ballZ2;

    angle += 45.0 * M_PI / 180.0;
    balB2[x] = sin(angle) * b_radius;
    balB2[y] = cos(angle) * b_radius;
    balB2[z] = ballZ2;

    angle += 45.0 * M_PI / 180.0;
    balB3[x] = sin(angle) * b_radius;
    balB3[y] = cos(angle) * b_radius;
    balB3[z] = ballZ2;

    angle += 45.0 * M_PI / 180.0;
    balB4[x] = sin(angle) * b_radius;
    balB4[y] = cos(angle) * b_radius;
    balB4[z] = ballZ2;

    angle += 45.0 * M_PI / 180.0;
    balB5[x] = sin(angle) * b_radius;
    balB5[y] = cos(angle) * b_radius;
    balB5[z] = ballZ2;

    angle += 45.0 * M_PI / 180.0;
    balB6[x] = sin(angle) * b_radius;
    balB6[y] = cos(angle) * b_radius;
    balB6[z] = ballZ2;

    angle += 45.0 * M_PI / 180.0;
    balB7[x] = sin(angle) * b_radius;
    balB7[y] = cos(angle) * b_radius;
    balB7[z] = ballZ2;

    angle += 45.0 * M_PI / 180.0;
    balB8[x] = sin(angle) * b_radius;
    balB8[y] = cos(angle) * b_radius;
    balB8[z] = ballZ2;

    setSpaceShipVertexData(engine->shipModeStatus());
    verticesToNormals(SPACESHIP_CONE_INDICES, v_cone, n_cone);
    verticesToNormals(SPACESHIP_BALL_INDICES, v_ball, n_ball);
}

/*! Set spaceship vertex data.
    Adjusts ship graphics when the ship mode is changing
    from ball mode to cone mode or vice versa according
    to mode change status counter.
*/
void GameWidget::setSpaceShipVertexData(GLfloat shipAnimationPhase)
{
#ifdef SMASHMINER_CONFIG_ENABLE_DEBUG_CHECKS

    if (shipAnimationPhase < 0.0f || shipAnimationPhase > 1.0f) {
        qDebug() << "GameWidget::setSpaceShipVertexData() : input out of valid range.";
        exit(EXIT_FAILURE);
    }

#endif  // SMASHMINER_CONFIG_ENABLE_DEBUG_CHECKS

    const GLfloat bmod = 1.0f + shipAnimationPhase * 0.65f;

    GLfloat *spcBall = spaceshipBallVertexData;

    int i = 0;
        
    // ball mode: north
    
    *(spcBall++) = balBC[x];
    *(spcBall++) = balBC[y];
    *(spcBall++) = balBC[z];

    *(spcBall++) = bmod * balB1[x];
    *(spcBall++) = bmod * balB1[y];
    *(spcBall++) = balB1[z];

    *(spcBall++) = bmod * balB2[x];
    *(spcBall++) = bmod * balB2[y];
    *(spcBall++) = balB2[z];

    // ball mode: north-east

    *(spcBall++) = balBC[x];
    *(spcBall++) = balBC[y];
    *(spcBall++) = balBC[z];
   
    *(spcBall++) = bmod * balB2[x];
    *(spcBall++) = bmod * balB2[y];
    *(spcBall++) = balB2[z];
   
    *(spcBall++) = bmod * balB3[x];
    *(spcBall++) = bmod * balB3[y];
    *(spcBall++) = balB3[z];

    // ball mode: east
    *(spcBall++) = balBC[x];
    *(spcBall++) = balBC[y];
    *(spcBall++) = balBC[z];
   
    *(spcBall++) = bmod * balB3[x];
    *(spcBall++) = bmod * balB3[y];
    *(spcBall++) = balB3[z];
   
    *(spcBall++) = bmod * balB4[x];
    *(spcBall++) = bmod * balB4[y];
    *(spcBall++) = balB4[z];

    // ball mode: south-east

    *(spcBall++) = balBC[x];
    *(spcBall++) = balBC[y];
    *(spcBall++) = balBC[z];
   
    *(spcBall++) = bmod * balB4[x];
    *(spcBall++) = bmod * balB4[y];
    *(spcBall++) = balB4[z];
   
    *(spcBall++) = bmod * balB5[x];
    *(spcBall++) = bmod * balB5[y];
    *(spcBall++) = balB5[z];

    // ball mode: south
    *(spcBall++) = balBC[x];
    *(spcBall++) = balBC[y];
    *(spcBall++) = balBC[z];
   
    *(spcBall++) = bmod * balB5[x];
    *(spcBall++) = bmod * balB5[y];
    *(spcBall++) = balB5[z];
   
    *(spcBall++) = bmod * balB6[x];
    *(spcBall++) = bmod * balB6[y];
    *(spcBall++) = balB6[z];

    // ball mode: south-west
    *(spcBall++) = balBC[x];
    *(spcBall++) = balBC[y];
    *(spcBall++) = balBC[z];
   
    *(spcBall++) = bmod * balB6[x];
    *(spcBall++) = bmod * balB6[y];
    *(spcBall++) = balB6[z];
   
    *(spcBall++) = bmod * balB7[x];
    *(spcBall++) = bmod * balB7[y];
    *(spcBall++) = balB7[z];

    // ball mode: west
    *(spcBall++) = balBC[x];
    *(spcBall++) = balBC[y];
    *(spcBall++) = balBC[z];
   
    *(spcBall++) = bmod * balB7[x];
    *(spcBall++) = bmod * balB7[y];
    *(spcBall++) = balB7[z];
   
    *(spcBall++) = bmod * balB8[x];
    *(spcBall++) = bmod * balB8[y];
    *(spcBall++) = balB8[z];

    // ball mode: north-west
    *(spcBall++) = balBC[x];
    *(spcBall++) = balBC[y];
    *(spcBall++) = balBC[z];
   
    *(spcBall++) = bmod * balB8[x];
    *(spcBall++) = bmod * balB8[y];
    *(spcBall++) = balB8[z];
   
    *(spcBall++) = bmod * balB1[x];
    *(spcBall++) = bmod * balB1[y];
    *(spcBall++) = balB1[z];

    const GLfloat cmod = 1.0f - shipAnimationPhase * 0.50f;

    i = 0;
    GLfloat *spcCone = spaceshipConeVertexData;

    // cone mode: wing right-up
    *(spcCone++) = conCe[x];
    *(spcCone++) = conCe[y];
    *(spcCone++) = conCe[z];

    *(spcCone++) = conB1[x];
    *(spcCone++) = conB1[y] * cmod;
    *(spcCone++) = conB1[z];

    *(spcCone++) = conB0[x];
    *(spcCone++) = conB0[y];
    *(spcCone++) = conB0[z];

    // cone mode: wing right-down
    *(spcCone++) = conCe[x];
    *(spcCone++) = conCe[y];
    *(spcCone++) = conCe[z];

    *(spcCone++) = conB0[x];
    *(spcCone++) = conB0[y];
    *(spcCone++) = conB0[z];

    *(spcCone++) = conB2[x];
    *(spcCone++) = conB2[y] * cmod;
    *(spcCone++) = conB2[z];


    // cone mode: wing left-down
    *(spcCone++) = conCe[x];
    *(spcCone++) = conCe[y];
    *(spcCone++) = conCe[z];

    *(spcCone++) = conD1[x];
    *(spcCone++) = conD1[y] * cmod;
    *(spcCone++) = conD1[z];

    *(spcCone++) = conD0[x];
    *(spcCone++) = conD0[y];
    *(spcCone++) = conD0[z];

    // cone mode: wing left-up
    *(spcCone++) = conCe[x];
    *(spcCone++) = conCe[y];
    *(spcCone++) = conCe[z];

    *(spcCone++) = conD0[x];
    *(spcCone++) = conD0[y];
    *(spcCone++) = conD0[z];

    *(spcCone++) = conD2[x];
    *(spcCone++) = conD2[y] * cmod;
    *(spcCone++) = conD2[z];

    // cone mode: wing up-left
    *(spcCone++) = conCe[x];
    *(spcCone++) = conCe[y];
    *(spcCone++) = conCe[z];

    *(spcCone++) = conA1[x] * cmod;
    *(spcCone++) = conA1[y];
    *(spcCone++) = conA1[z];

    *(spcCone++) = conA0[x];
    *(spcCone++) = conA0[y];
    *(spcCone++) = conA0[z];

    // cone mode: wing up-right
    *(spcCone++) = conCe[x];
    *(spcCone++) = conCe[y];
    *(spcCone++) = conCe[z];

    *(spcCone++) = conA0[x];
    *(spcCone++) = conA0[y];
    *(spcCone++) = conA0[z];

    *(spcCone++) = conA2[x] * cmod;
    *(spcCone++) = conA2[y];
    *(spcCone++) = conA2[z];

    // cone mode: wing down-right
    *(spcCone++) = conCe[x];
    *(spcCone++) = conCe[y];
    *(spcCone++) = conCe[z];

    *(spcCone++) = conC1[x] * cmod;
    *(spcCone++) = conC1[y];
    *(spcCone++) = conC1[z];

    *(spcCone++) = conC0[x];
    *(spcCone++) = conC0[y];
    *(spcCone++) = conC0[z];

    // cone mode: wing down-left
    *(spcCone++) = conCe[x];
    *(spcCone++) = conCe[y];
    *(spcCone++) = conCe[z];

    *(spcCone++) = conC0[x];
    *(spcCone++) = conC0[y];
    *(spcCone++) = conC0[z];

    *(spcCone++) = conC2[x] * cmod;
    *(spcCone++) = conC2[y];
    *(spcCone++) = conC2[z];
}

/// Initiates asteroid vertex, normal and light data.
void GameWidget::initAsteroid()
{
    GLfloat *v_big = asteroidVertexData;
    GLfloat *n_big = asteroidNormalData;
    GLfloat *c_big = asteroidColourData;
    GLfloat *v_medA = asteroidMediumAVertexData;
    GLfloat *n_medA = asteroidMediumANormalData;
    GLfloat *c_medA = asteroidMediumAColourData;
    GLfloat *v_medB = asteroidMediumBVertexData;
    GLfloat *n_medB = asteroidMediumBNormalData;
    GLfloat *c_medB = asteroidMediumBColourData;
    GLfloat *v_medC = asteroidMediumCVertexData;
    GLfloat *n_medC = asteroidMediumCNormalData;
    GLfloat *c_medC = asteroidMediumCColourData;

    /* Meteor points:
    //
    //                             meA 
    //                     ________
    //     meD    ________/       /\
    //       ____/               /  \_
    //      |                   /     \
    //      / .                |       \
    //     |   .               |        \_
    //     /    .             /           \
    //    |       .         /              \
    //    |         .      /      A      . .\  meE
    //   /            .   /        .  .      | 
    //   |    C        . /.mCU/D             |
    //   |              /\__                 |
    //  /           __/ .   \___            |
    //  |        __/     .      \__         |
    //  |     __/        .         \__      |
    // /    _/           .            \_   |
    // |  _/             .              \_ |
    // |_/               .  B             \|
    //  \__              .                / meB
    // meC \___           .           ___/
    //         \____      .       ___/
    //              \___  .  ____/
    //                  \___/ 
    //                     meF
    */
    GLfloat sc = GameEngine::GameObjectRadiusAsteroidL;

    GLfloat random;

    // Center point values for asteroid
    GLfloat meCenX = 0.0f;
    GLfloat meCenY = 0.0f;
    GLfloat meCenZup = sc * +0.9f;
    GLfloat meCenZdn = sc * -0.9f;

    GLfloat meOuterZ = sc * 0.0f;

    random = (engine->getRandomF() - 0.50) * 0.50;
    GLfloat meAx = sc * sin(0.0 * M_PI / 180.0 + random);
    GLfloat meAy = sc * cos(0.0 * M_PI / 180.0 + random);
    random = (engine->getRandomF() - 0.50) * 0.50;
    GLfloat meBx = sc * sin(120.0 * M_PI / 180.0 + random);
    GLfloat meBy = sc * cos(120.0 * M_PI / 180.0 + random);
    random = (engine->getRandomF() - 0.50) * 0.50;
    GLfloat meCx = sc * sin(240.0 * M_PI / 180.0 + random);
    GLfloat meCy = sc * cos(240.0 * M_PI / 180.0 + random);

    random = (engine->getRandomF() - 0.50) * 0.50;
    GLfloat meDx = sc * sin(300.0 * M_PI / 180.0 + random);
    GLfloat meDy = sc * cos(300.0 * M_PI / 180.0 + random);
    random = (engine->getRandomF() - 0.50) * 0.50;
    GLfloat meEx = sc * sin(60.0 * M_PI / 180.0 + random);
    GLfloat meEy = sc * cos(60.0 * M_PI / 180.0 + random);
    random = (engine->getRandomF() - 0.50) * 0.50;
    GLfloat meFx = sc * sin(180.0 * M_PI / 180.0 + random);
    GLfloat meFy = sc * cos(180.0 * M_PI / 180.0 + random);

    GLfloat mCU[] = { meCenX, meCenY, meCenZup };
    GLfloat mCD[] = { meCenX, meCenY, meCenZdn }; 
    GLfloat meA[] = { meAx, meAy, meOuterZ + (engine->getRandomF() - 0.50) * sc * 1.00 };
    GLfloat meB[] = { meBx, meBy, meOuterZ + (engine->getRandomF() - 0.50) * sc * 1.00 };
    GLfloat meC[] = { meCx, meCy, meOuterZ + (engine->getRandomF() - 0.50) * sc * 1.00 };
    GLfloat meD[] = { meDx, meDy, meOuterZ + (engine->getRandomF() - 0.50) * sc * 1.00 };
    GLfloat meE[] = { meEx, meEy, meOuterZ + (engine->getRandomF() - 0.50) * sc * 1.00 };
    GLfloat meF[] = { meFx, meFy, meOuterZ + (engine->getRandomF() - 0.50) * sc * 1.00 };

    // colours for each point
    GLfloat color_aCU_o[3];     // i=0 out
    GLfloat color_aCD_o[3];     // i=1 out
    GLfloat color_asA_o[3];     // i=2 out
    GLfloat color_asB_o[3];     // i=3 out
    GLfloat color_asC_o[3];     // i=4 out
    GLfloat color_asD[3];       // i=5 out
    GLfloat color_asE[3];       // i=6 out
    GLfloat color_asF[3];       // i=7 out
    GLfloat color_aCU_i[3];     // i=8 in
    GLfloat color_aCD_i[3];     // i=9 in
    GLfloat color_asA_i[3];     // i=10 in
    GLfloat color_asB_i[3];     // i=11 in
    GLfloat color_asC_i[3];     // i=12 in

    randomGray(color_aCU_o);
    randomBrown(color_aCD_o);
    randomGray(color_asA_o);
    randomGray(color_asB_o);
    randomGray(color_asC_o);
    randomBrown(color_asD);
    randomBrown(color_asE);
    randomBrown(color_asF);

    randomRed(color_aCU_i);
    randomRed(color_aCD_i);
    randomRed(color_asA_i);
    randomRed(color_asB_i);
    randomRed(color_asC_i);

    GLfloat *colortab[] = {
        color_aCU_o, color_aCD_o, color_asA_o, color_asB_o, color_asC_o,
        color_asD, color_asE, color_asF, color_aCU_i, color_aCD_i,
        color_asA_i, color_asB_i, color_asC_i
    };

    int big_colormap[] = {

        // -- Up side --

        0, 2, 6,    // CU - A - E
        0, 6, 3,    // CU - E - B
        0, 3, 7,    // CU - B - F
        0, 7, 4,    // CU - F - C
        0, 4, 5,    // CU - C - D
        0, 5, 2,    // CU - D - A

        // -- Down side --

        1, 6, 2,    // CD - E - A
        1, 3, 6,    // CD - B - E
        1, 7, 3,    // CD - F - B
        1, 4, 7,    // CD - C - F
        1, 5, 4,    // CD - D - C
        1, 2, 5     // CD - A - D

    };

    int mediumAcolorMap[] = {

        // -- Up side --

        0, 2, 6,    // CU - A - E
        0, 6, 3,    // CU - E - B

        // -- Down side --
        
        1, 6, 2,    // CD - E - A
        1, 2, 6,    // CD - B - E

        // -- side towards medium asteroid C

        10, 8, 9,   // A - CU - CD

        // -- side towards medium asteroid B

        8, 11, 9    // CU - B - CD
    };

    int mediumBcolorMap[] = {

        // -- Up side --

        0, 3, 7,    // CU - B - F
        0, 7, 4,    // CU - F - C

        // -- Down side --
        
        1, 7, 3,    // CD - F - B
        1, 4, 7,    // CD - C - F

        // -- side towards medium asteroid A

       11, 8, 9,   // B - CU - CD

        // -- side towards medium asteroid C

        8, 12, 9    // CU - C - CD
    };

    int mediumCcolorMap[] = {

        // -- Up side --

        0, 4, 5,    // CU - C - D
        0, 5, 2,    // CU - D - A

        // -- Down side --
        
        1, 5, 4,    // CD - D - C
        1, 2, 5,    // CD - A - D

        // -- side towards medium asteroid C

        12, 8, 9,   // C - CU - CD

        // -- side towards medium asteroid B

        8, 10, 9    // CU - A - CD
    };


    const GLfloat medAXFix = (mCU[x] + mCD[x] + meA[x] + meE[x] + meB[x]) / 5.0f;
    const GLfloat medAYFix = (mCU[y] + mCD[y] + meA[y] + meE[y] + meB[y]) / 5.0f;
    const GLfloat medAZFix = (mCU[z] + mCD[z] + meA[z] + meE[z] + meB[z]) / 5.0f;

    GLfloat asteroidMediumA[] = {

        // -- Up --
        
        // CU - A - E 
        mCU[x]-medAXFix, mCU[y]-medAYFix, mCU[z]-medAZFix,
        meA[x]-medAXFix, meA[y]-medAYFix, meA[z]-medAZFix,
        meE[x]-medAXFix, meE[y]-medAYFix, meE[z]-medAZFix,

        // CU - E - B 
        mCU[x]-medAXFix, mCU[y]-medAYFix, mCU[z]-medAZFix,
        meE[x]-medAXFix, meE[y]-medAYFix, meE[z]-medAZFix,
        meB[x]-medAXFix, meB[y]-medAYFix, meB[z]-medAZFix,

        // -- Down --

        // CD - E - A
        mCD[x]-medAXFix, mCD[y]-medAYFix, mCD[z]-medAZFix,
        meE[x]-medAXFix, meE[y]-medAYFix, meE[z]-medAZFix,
        meA[x]-medAXFix, meA[y]-medAYFix, meA[z]-medAZFix,

        // CD - B - E
        mCD[x]-medAXFix, mCD[y]-medAYFix, mCD[z]-medAZFix,
        meB[x]-medAXFix, meB[y]-medAYFix, meB[z]-medAZFix,
        meE[x]-medAXFix, meE[y]-medAYFix, meE[z]-medAZFix,

        // Side towards medium asteroid C

        // CU - CD - A
        meA[x]-medAXFix, meA[y]-medAYFix, meA[z]-medAZFix,
        mCU[x]-medAXFix, mCU[y]-medAYFix, mCU[z]-medAZFix,
        mCD[x]-medAXFix, mCD[y]-medAYFix, mCD[z]-medAZFix,

        // Side towards medium asteroid B

        // CU - CD - B
        mCU[x]-medAXFix, mCU[y]-medAYFix, mCU[z]-medAZFix,
        meB[x]-medAXFix, meB[y]-medAYFix, meB[z]-medAZFix,
        mCD[x]-medAXFix, mCD[y]-medAYFix, mCD[z]-medAZFix
    };

    const GLfloat medBXFix = (mCU[x] + mCD[x] + meB[x] + meF[x] + meC[x]) / 5.0f;
    const GLfloat medBYFix = (mCU[y] + mCD[y] + meB[y] + meF[y] + meC[y]) / 5.0f;
    const GLfloat medBZFix = (mCU[z] + mCD[z] + meB[z] + meF[z] + meC[z]) / 5.0f;

    GLfloat asteroidMediumB[] = {

        // -- Up --
        
        // CU - B - F 
        mCU[x]-medBXFix, mCU[y]-medBYFix, mCU[z]-medBZFix,
        meB[x]-medBXFix, meB[y]-medBYFix, meB[z]-medBZFix,
        meF[x]-medBXFix, meF[y]-medBYFix, meF[z]-medBZFix,

        // CU - F - C 
        mCU[x]-medBXFix, mCU[y]-medBYFix, mCU[z]-medBZFix,
        meF[x]-medBXFix, meF[y]-medBYFix, meF[z]-medBZFix,
        meC[x]-medBXFix, meC[y]-medBYFix, meC[z]-medBZFix,

        // -- Down --

        // CD - F - B
        mCD[x]-medBXFix, mCD[y]-medBYFix, mCD[z]-medBZFix,
        meF[x]-medBXFix, meF[y]-medBYFix, meF[z]-medBZFix,
        meB[x]-medBXFix, meB[y]-medBYFix, meB[z]-medBZFix,

        // CD - C - F
        mCD[x]-medBXFix, mCD[y]-medBYFix, mCD[z]-medBZFix,
        meC[x]-medBXFix, meC[y]-medBYFix, meC[z]-medBZFix,
        meF[x]-medBXFix, meF[y]-medBYFix, meF[z]-medBZFix,

        // Side towards medium asteroid A

        // CU - CD - B
        meB[x]-medBXFix, meB[y]-medBYFix, meB[z]-medBZFix,
        mCU[x]-medBXFix, mCU[y]-medBYFix, mCU[z]-medBZFix,
        mCD[x]-medBXFix, mCD[y]-medBYFix, mCD[z]-medBZFix,

        // Side towards medium asteroid C

        // CU - CD - C
        mCU[x]-medBXFix, mCU[y]-medBYFix, mCU[z]-medBZFix,
        meC[x]-medBXFix, meC[y]-medBYFix, meC[z]-medBZFix,
        mCD[x]-medBXFix, mCD[y]-medBYFix, mCD[z]-medBZFix
    };
 
    const GLfloat medCXFix = (mCU[x] + mCD[x] + meC[x] + meD[x] + meA[x]) / 5.0f;
    const GLfloat medCYFix = (mCU[y] + mCD[y] + meC[y] + meD[y] + meA[y]) / 5.0f;
    const GLfloat medCZFix = (mCU[z] + mCD[z] + meC[z] + meD[z] + meA[z]) / 5.0f;

    GLfloat asteroidMediumC[] = {
        // CU - C - D
        mCU[x]-medCXFix, mCU[y]-medCYFix, mCU[z]-medCZFix,
        meC[x]-medCXFix, meC[y]-medCYFix, meC[z]-medCZFix,
        meD[x]-medCXFix, meD[y]-medCYFix, meD[z]-medCZFix,

        // CU - D - A
        mCU[x]-medCXFix, mCU[y]-medCYFix, mCU[z]-medCZFix,
        meD[x]-medCXFix, meD[y]-medCYFix, meD[z]-medCZFix,
        meA[x]-medCXFix, meA[y]-medCYFix, meA[z]-medCZFix,

        // CD - D - C
        mCD[x]-medCXFix, mCD[y]-medCYFix, mCD[z]-medCZFix,
        meD[x]-medCXFix, meD[y]-medCYFix, meD[z]-medCZFix,
        meC[x]-medCXFix, meC[y]-medCYFix, meC[z]-medCZFix,

        // CD - A - D
        mCD[x]-medCXFix, mCD[y]-medCYFix, mCD[z]-medCZFix,
        meA[x]-medCXFix, meA[y]-medCYFix, meA[z]-medCZFix,
        meD[x]-medCXFix, meD[y]-medCYFix, meD[z]-medCZFix,

        // Side towards medium asteroid A
        meC[x]-medCXFix, meC[y]-medCYFix, meC[z]-medCZFix,
        mCU[x]-medCXFix, mCU[y]-medCYFix, mCU[z]-medCZFix,
        mCD[x]-medCXFix, mCD[y]-medCYFix, mCD[z]-medCZFix,

        // Side towards medium asteroid B
        mCU[x]-medCXFix, mCU[y]-medCYFix, mCU[z]-medCZFix,
        meA[x]-medCXFix, meA[y]-medCYFix, meA[z]-medCZFix,
        mCD[x]-medCXFix, mCD[y]-medCYFix, mCD[z]-medCZFix
    };

    GLfloat asteroidBig[] = {

        // -- Up side --

        // CU - A - E
        mCU[x], mCU[y], mCU[z],
        meA[x], meA[y], meA[z],
        meE[x], meE[y], meE[z],

        // CU - E - B
        mCU[x], mCU[y], mCU[z],
        meE[x], meE[y], meE[z],
        meB[x], meB[y], meB[z],

        // CU - B - F
        mCU[x], mCU[y], mCU[z],
        meB[x], meB[y], meB[z],
        meF[x], meF[y], meF[z],

        // CU - F - C
        mCU[x], mCU[y], mCU[z],
        meF[x], meF[y], meF[z],
        meC[x], meC[y], meC[z],

        // CU - C - D
        mCU[x], mCU[y], mCU[z],
        meC[x], meC[y], meC[z],
        meD[x], meD[y], meD[z],

        // CU - D - A
        mCU[x], mCU[y], mCU[z],
        meD[x], meD[y], meD[z],
        meA[x], meA[y], meA[z],

        // -- Down side --

        // CD - E - A
        mCD[x], mCD[y], mCD[z],
        meE[x], meE[y], meE[z],
        meA[x], meA[y], meA[z],

        // CD - B - E
        mCD[x], mCD[y], mCD[z],
        meB[x], meB[y], meB[z],
        meE[x], meE[y], meE[z],

        // CD - F - B
        mCD[x], mCD[y], mCD[z],
        meF[x], meF[y], meF[z],
        meB[x], meB[y], meB[z],

        // CD - C - F
        mCD[x], mCD[y], mCD[z],
        meC[x], meC[y], meC[z],
        meF[x], meF[y], meF[z],

        // CD - D - C
        mCD[x], mCD[y], mCD[z],
        meD[x], meD[y], meD[z],
        meC[x], meC[y], meC[z],

        // CD - A - D
        mCD[x], mCD[y], mCD[z],
        meA[x], meA[y], meA[z],
        meD[x], meD[y], meD[z]

    };

    for (int i = 0;i < ASTEROID_INDICES;i++)
        v_big[i] = asteroidBig[i];

    verticesToNormals(ASTEROID_INDICES, v_big, n_big);

    for (int i = 0;i < ASTEROID_INDICES / 3;i++) {   // 1 vertex = 3 coordinates
        const int index = big_colormap[i];

        c_big[i * 3 + 0] = colortab[index][0];
        c_big[i * 3 + 1] = colortab[index][1];
        c_big[i * 3 + 2] = colortab[index][2];
    }

    for (int i = 0;i < ASTEROID_MEDIUM_INDICES;i++) {
        v_medA[i] = asteroidMediumA[i];
        v_medB[i] = asteroidMediumB[i];
        v_medC[i] = asteroidMediumC[i];
    }

    verticesToNormals(ASTEROID_MEDIUM_INDICES, v_medA, n_medA);
    verticesToNormals(ASTEROID_MEDIUM_INDICES, v_medB, n_medB);
    verticesToNormals(ASTEROID_MEDIUM_INDICES, v_medC, n_medC);

    for (int i = 0; i < ASTEROID_MEDIUM_INDICES / 3; i++) {

        const int indA = mediumAcolorMap[i];
        const int indB = mediumBcolorMap[i];
        const int indC = mediumCcolorMap[i];

        c_medA[i * 3 + 0] = colortab[indA][0];
        c_medA[i * 3 + 1] = colortab[indA][1];
        c_medA[i * 3 + 2] = colortab[indA][2];

        c_medB[i * 3 + 0] = colortab[indB][0];
        c_medB[i * 3 + 1] = colortab[indB][1];
        c_medB[i * 3 + 2] = colortab[indB][2];

        c_medC[i * 3 + 0] = colortab[indC][0];
        c_medC[i * 3 + 1] = colortab[indC][1];
        c_medC[i * 3 + 2] = colortab[indC][2];
    }

    engine->asteroidMediumATranslationX = medAXFix;
    engine->asteroidMediumATranslationY = medAYFix;
    engine->asteroidMediumATranslationZ = medAZFix;

    engine->asteroidMediumBTranslationX = medBXFix;
    engine->asteroidMediumBTranslationY = medBYFix;
    engine->asteroidMediumBTranslationZ = medBZFix;

    engine->asteroidMediumCTranslationX = medCXFix;
    engine->asteroidMediumCTranslationY = medCYFix;
    engine->asteroidMediumCTranslationZ = medCZFix;
}

/// Initiates mineral vertex, normal and light data.
void GameWidget::initMineral()
{
    GLfloat *vertexData = mineralVertexData;
    GLfloat *normalData = mineralNormalData;

    GLfloat *colourDataA = mineralAColourData;
    GLfloat *colourDataB = mineralBColourData;
    GLfloat *colourDataC = mineralCColourData;
    GLfloat *colourDataD = mineralDColourData;

    // blue
    colourDataA[0] = 0.0f;
    colourDataA[1] = 0.0f;
    colourDataA[2] = 1.0f;
    colourDataA[3] = 1.0f;

    // green
    colourDataB[0] = 0.0f;
    colourDataB[1] = 0.8f;
    colourDataB[2] = 0.0f;
    colourDataB[3] = 1.0f;

    // white
    colourDataC[0] = 0.7f;
    colourDataC[1] = 0.7f;
    colourDataC[2] = 0.7f;
    colourDataC[3] = 1.0f;

    // yellow
    colourDataD[0] = 0.8f;
    colourDataD[1] = 0.8f;
    colourDataD[2] = 0.0f;
    colourDataD[3] = 1.0f;

#ifdef SMASHMINER_CONFIG_USE_OPENGL_ES_2

    GLes2MakeLightMaterialData(lightAmbient, colourDataA, mineralALightsAmbientLmData);
    GLes2MakeLightMaterialData(lightDiffuse, colourDataA, mineralALightsDiffuseLmData);

    GLes2MakeLightMaterialData(lightAmbient, colourDataB, mineralBLightsAmbientLmData);
    GLes2MakeLightMaterialData(lightDiffuse, colourDataB, mineralBLightsDiffuseLmData);

    GLes2MakeLightMaterialData(lightAmbient, colourDataC, mineralCLightsAmbientLmData);
    GLes2MakeLightMaterialData(lightDiffuse, colourDataC, mineralCLightsDiffuseLmData);

    GLes2MakeLightMaterialData(lightAmbient, colourDataD, mineralDLightsAmbientLmData);
    GLes2MakeLightMaterialData(lightDiffuse, colourDataD, mineralDLightsDiffuseLmData);

#endif  // SMASHMINER_CONFIG_USE_OPENGL_ES_2

    /*
    // Side1:              Side2:             Side3:             Side4:
    //                                                                               
    //           mE                 mE                 mE                 mE
    //           / \                / \                / \                / \
    //          /   \              /   \              /   \              /   \
    //         /     \            /     \            /     \            /     \
    //        /_______\          /_______\          /_______\          /_______\
    //     mD \       / mC    mC \       / mB    mB \       / mA    mA \       / mD
    //         \     /            \     /            \     /            \     /
    //          \   /              \   /              \   /              \   /
    //           \ /                \ /                \ /                \ /
    //           mF                 mF                 mF                 mF        
    */

    GLfloat scale = GameEngine::GameObjectRadiusMineral;
    GLfloat height = scale * 0.9f;
    GLfloat width = scale * 1.1f;

    GLfloat mA[] = {-width/2, 0.0f,-width/2 };
    GLfloat mB[] = { width/2, 0.0f,-width/2 };
    GLfloat mC[] = { width/2, 0.0f, width/2 };
    GLfloat mD[] = {-width/2, 0.0f, width/2 };
    GLfloat mE[] = { 0.0f, height, 0.0f }; 
    GLfloat mF[] = { 0.0f,-height, 0.0f }; 

    GLfloat vData[] = {

        // - Side1 -

        // mD - mE - mC
        mD[x], mD[y], mD[z],
        mE[x], mE[y], mE[z],
        mC[x], mC[y], mC[z],

        // mD - mC - mF
        mD[x], mD[y], mD[z],
        mC[x], mC[y], mC[z],
        mF[x], mF[y], mF[z],
        
        // - Side2 -

        // mC - mE - mB
        mC[x], mC[y], mC[z],
        mE[x], mE[y], mE[z],
        mB[x], mB[y], mB[z],

        // mC - mB - mF
        mC[x], mC[y], mC[z],
        mB[x], mB[y], mB[z],
        mF[x], mF[y], mF[z],

        // Side3

        // mB - mE - mA
        mB[x], mB[y], mB[z],
        mE[x], mE[y], mE[z],
        mA[x], mA[y], mA[z],

        // mB - mA - mF
        mB[x], mB[y], mB[z],
        mA[x], mA[y], mA[z],
        mF[x], mF[y], mF[z],

        // Side4
        
        // mA - mE - mD
        mA[x], mA[y], mA[z],
        mE[x], mE[y], mE[z],
        mD[x], mD[y], mD[z],

        // mA - mD - mF
        mA[x], mA[y], mA[z],
        mD[x], mD[y], mD[z],
        mF[x], mF[y], mF[z]
    
        // indices: 8 triangles * 3 vertices * 3 coordinates = 72 indices
    };

    for (int i = 0; i < MINERAL_INDICES; i++) 
        vertexData[i] = vData[i];

    verticesToNormals(MINERAL_INDICES, vertexData, normalData);  
}

/// Get randomized color for drawing
void GameWidget::randomRed(GLfloat * color)
{
    GLfloat r1 = 0.8f * (GLfloat) rand() / (GLfloat) RAND_MAX;
    GLfloat r2 = 0.4f * (GLfloat) rand() / (GLfloat) RAND_MAX;

    color[0] = 0.6f + r1;
    color[1] = (r1 > 0.4f ? r2 : 0.0f);
    color[2] = color[1];
}

/// Get randomized color for drawing
void GameWidget::randomGray(GLfloat * color)
{
    GLfloat r1 = 0.6f * (GLfloat) rand() / (GLfloat) RAND_MAX;

    color[0] = 0.3f + r1;
    color[1] = color[0];
    color[2] = color[0];
}

/// Get randomized color for drawing
void GameWidget::randomBrown(GLfloat * color)
{
    randomGray(color);

    color[0] *= 1.2f;
    color[2] /= 1.2f;

    if (color[0] > 1.0) color[0] = 1.0;
}

#define NORMAL_VECTOR_LENGTH    1.0

/*! Compute \a normal for each vertex in game object vertex data. 
 * Each normal consists of x, y and z coordinate (consumes three indices).
 *
 * \param indices Amount of indices in vertex data.
 * \param[in] vertex Game object vertex data.
 * \param[out] normal To store game object normal data for each vertex.
 */
void GameWidget::verticesToNormals(int indices, GLfloat *vertex, GLfloat *normal)
{
    for (int i = 0; i < indices / 9; i++) {     // 1 triangle = 3 vertices = 9 coordinates
        const int iA = i * 9 + 0;   // index of 1st vertex/normal
        const int iB = i * 9 + 3;   // index of 2nd vertex/normal
        const int iC = i * 9 + 6;   // index of 3rd vertex/normal

        GLfloat normalTmp[3];
        computeNormalForTriangle(normalTmp, &vertex[iA], &vertex[iB], &vertex[iC]);

        for (int copy = 0;copy < 3;copy++) {
            normal[iA + copy] = normalTmp[copy];
            normal[iB + copy] = normalTmp[copy];
            normal[iC + copy] = normalTmp[copy];
        }
    }
}

/*! Compute a normal (\a normalValue) from triangle defined by three given vertices
 *
 * \param[out] normalValue Normal of a triangle defined by three given vertices 
 * \param[in] point1 Triangle vertex
 * \param[in] point2 Triangle vertex 
 * \param[in] point3 Triangle vertex 
 */
void GameWidget::computeNormalForTriangle(GLfloat *normalValue, GLfloat *point1, GLfloat *point2, GLfloat *point3)
{
    GLfloat vect1[3];
    GLfloat vect2[3];

    // compute vectors point1->point2 and point1->point3

    for (int i = 0;i < 3;i++) {
        vect1[i] = point2[i] - point1[i];
        vect2[i] = point3[i] - point1[i];
    }

    computeNormalForVectors(normalValue, vect1, vect2);
}

/// Compute \a normalValue from vectors: \a vector1 and \a vector2.
void GameWidget::computeNormalForVectors(GLfloat *normalValue, GLfloat *vector1, GLfloat *vector2)
{
    // compute cross product of the vectors

    normalValue[0] = vector1[1] * vector2[2] - vector1[2] * vector2[1];
    normalValue[1] = vector1[2] * vector2[0] - vector1[0] * vector2[2];
    normalValue[2] = vector1[0] * vector2[1] - vector1[1] * vector2[0];

    // normalize the result to a unit vector

    GameEngine::normalizeVect3D_GLfloat(normalValue);
}

/// Initiates ufo vertex, normal and light data.
void GameWidget::initUfo(GLfloat *ufoColor1Data, GLfloat *ufoColor1NormalData, 
                         GLfloat *ufoColor2Data,GLfloat *ufoColor2NormalData, 
                         GLfloat *ufoLightsData, GLfloat *ufoLightsNormalData) 
{

    GLfloat scale = GameEngine::GameObjectRadiusUFO;

    // UFO graphics variables
    GLfloat ufoCenterRatio = 0.3f;
    GLfloat center = 0.0f;
    GLfloat height = 1.0f * scale;
    GLfloat centerY = height / 2;
    GLfloat centerZ = 1.0f * scale;
    GLfloat sideX = 1.0f * scale;
    GLfloat sideY = (height * ufoCenterRatio) / 2;
    GLfloat cornerZ = sin(45.0 * M_PI / 180.0) * scale;
    GLfloat cornerX = sin(45.0 * M_PI / 180.0) * scale;

    GLfloat lightDist = 1.02 * scale;
    GLfloat lightAngle = 20.0;

    GLfloat cornerLightX = sin(lightAngle * M_PI / 180.0) * lightDist;
    GLfloat cornerLightZ = cos(lightAngle * M_PI / 180.0) * lightDist;

    ufoColor1ColorData[0] = 1.5f;
    ufoColor1ColorData[1] = 0.5f;
    ufoColor1ColorData[2] = 0.0f;
    ufoColor1ColorData[3] = 1.0f;

    ufoColor2ColorData[0] = 0.5f;
    ufoColor2ColorData[1] = 1.5f;
    ufoColor2ColorData[2] = 0.0f;
    ufoColor2ColorData[3] = 1.0f;

    ufoLightsColorData[0] = 1.0f;
    ufoLightsColorData[1] = 1.0f;
    ufoLightsColorData[2] = 1.0f;
    ufoLightsColorData[3] = 1.0f;

#ifdef SMASHMINER_CONFIG_USE_OPENGL_ES_2

    GLes2MakeLightMaterialData(lightAmbient, ufoColor1ColorData, ufoColor1AmbientLmData);
    GLes2MakeLightMaterialData(lightDiffuse, ufoColor1ColorData, ufoColor1DiffuseLmData);
    GLes2MakeLightMaterialData(lightAmbient, ufoColor2ColorData, ufoColor2AmbientLmData);
    GLes2MakeLightMaterialData(lightDiffuse, ufoColor2ColorData, ufoColor2DiffuseLmData);
    GLes2MakeLightMaterialData(lightAmbient, ufoLightsColorData, ufoLightsAmbientLmData);
    GLes2MakeLightMaterialData(lightDiffuse, ufoLightsColorData, ufoLightsDiffuseLmData);

#endif  // SMASHMINER_CONFIG_USE_OPENGL_ES_2

    GLfloat ufoColor1[] = {
        // GRAPHICS FOR BOTTOM PART OF UFO
        // UFO (nonagon) from bottom (top) coordinate points:
        //                      BACK
        //                        ^
        //                  *************
        // LEFT-BACK     ********************  RIGHT-BACK
        //            ************************
        //          ***************************
        // LEFT  < ***************x CENTER*******> RIGHT
        //          ***************************
        //           *************************
        // LEFT-FRONT *********************  RIGHT-FRONT
        //                ****************
        //                        -
        //                     FRONT
        //

        // CENTER
        center, -centerY, center,
        // RIGHT-BACK
        cornerX, -sideY, -cornerZ,
        // BACK
        center, -sideY, -centerZ,

        // CENTER
        center, -centerY, center,
        // LEFT-BACK
        -cornerX, -sideY, -cornerZ,
        // LEFT
        -sideX, -sideY, center,

        // CENTER
        center, -centerY, center,
        // LEFT-FRONT
        -cornerX, -sideY, cornerZ,
        // FRONT
        center, -sideY, centerZ,


        // CENTER
        center, -centerY, center,
        // RIGHT-FRONT
        cornerX, -sideY, cornerZ,
        // RIGHT
        sideX, -sideY, center,

        // GRAPHICS FOR CENTER PART OF UFO
        /* UFO center from front side coordinate points:
        // TOP-LEFT    TOP-LEFT-CENTER     TOP-CENTER     TOP-RIGHT-CENTER      TOP-RIGHT
        //   x-----------------x-----------------x----------------x----------------x
        //   |                 |                 |                |                |
        //   |                 |                 |                |                |
        //   |                 |                 |                |                |
        //   x-----------------x-----------------x----------------x----------------x
        // BOTTOM-LEFT BOTTOM-LEFT-CENTER  BOTTOM-CENTER  BOTTOM-RIGHT-CENTER   BOTTOM-RIGHT
        */

        // UFO CENTER-FRONT
        // FRONT-LEFT SQUARE
        // TOP-LEFT
        -sideX, sideY, center,
        // BOTTOM-LEFT-CENTER
        -cornerX, -sideY, cornerZ,
        // BOTTOM-LEFT
        -sideX, -sideY, center,

        // BOTTOM-LEFT-CENTER
        -cornerX, -sideY, cornerZ,
        // TOP-LEFT
        -sideX, sideY, center,
        // TOP-LEFT-CENTER
        -cornerX, sideY, cornerZ,

        // FRONT-RIGHT-CENTER SQUARE
        // TOP-CENTER
        center, sideY, centerZ,
        // BOTTOM-RIGHT-CENTER
        cornerX, -sideY, cornerZ,
        // BOTTOM-CENTER
        center, -sideY, centerZ,

        // TOP-CENTER
        center, sideY, centerZ,
        // TOP-RIGHT-CENTER
        cornerX, sideY, cornerZ,
        // BOTTOM-RIGHT-CENTER
        cornerX, -sideY, cornerZ,

        // BACK-LEFT-CENTER SQUARE
        // TOP-LEFT-CENTER
        -cornerX, sideY, -cornerZ,
        // BOTTOM-LEFT-CENTER
        -cornerX, -sideY, -cornerZ,
        // BOTTOM-CENTER
        center, -sideY, -centerZ,

        // TOP-CENTER
        center, sideY, -centerZ,
        // TOP-LEFT-CENTER
        -cornerX, sideY, -cornerZ,
        // BOTTOM-CENTER
        center, -sideY, -centerZ,

        // BACK-RIGHT SQUARE
        // TOP-RIGHT
        sideX, sideY, center,
        // BOTTOM-RIGHT-CENTER
        cornerX, -sideY, -cornerZ,
        // BOTTOM-RIGHT
        sideX, -sideY, center,

        // BOTTOM-RIGHT-CENTER
        cornerX, -sideY, -cornerZ,
        // TOP-RIGHT
        sideX, sideY, center,
        // TOP-RIGHT-CENTER
        cornerX, sideY, -cornerZ,

        // DRAW TOP PART OF UFO
        //----------------------
        // CENTER
        center, centerY, center,
        // BACK
        center, sideY, -centerZ,
        // RIGHT-BACK
        cornerX, sideY, -cornerZ,

        // CENTER
        center, centerY, center,
        // LEFT
        -sideX, sideY, center,
        // LEFT-BACK
        -cornerX, sideY, -cornerZ,

        // CENTER
        center, centerY, center,
        // FRONT
        center, sideY, centerZ,
        // LEFT-FRONT
        -cornerX, sideY, cornerZ,

        // CENTER
        center, centerY, center,
        // RIGHT
        sideX, sideY, center,
        // RIGHT-FRONT
        cornerX, sideY, cornerZ
    };

    GLfloat ufoColor2[] = {
        // GRAPHICS FOR BOTTOM PART OF UFO
        // UFO (nonagon) from bottom (top) coordinate points:
        //                      BACK
        //                        ^
        //                  *************
        // LEFT-BACK     ********************  RIGHT-BACK
        //            ************************
        //          ***************************
        // LEFT  < ***************x CENTER*******> RIGHT
        //          ***************************
        //           *************************
        // LEFT-FRONT *********************  RIGHT-FRONT
        //                ****************
        //                        -
        //                     FRONT
        //

        // CENTER
        center, -centerY, center,
        // BACK
        center, -sideY, -centerZ,
        // LEFT-BACK
        -cornerX, -sideY, -cornerZ,

        // CENTER
        center, -centerY, center,
        // LEFT
        -sideX, -sideY, center,
        // LEFT-FRONT
        -cornerX, -sideY, cornerZ,

        // CENTER
        center, -centerY, center,
        // FRONT
        center, -sideY, centerZ,
        // RIGHT-FRONT
        cornerX, -sideY, cornerZ,

        // CENTER
        center, -centerY, center,
        // RIGHT
        sideX, -sideY, center,
        // RIGHT-BACK
        cornerX, -sideY, -cornerZ,

        // DRAW CENTER PART OF UFO
        //------------------------

        /* UFO center from front side coordinate points:
        // TOP-LEFT    TOP-LEFT-CENTER     TOP-CENTER     TOP-RIGHT-CENTER      TOP-RIGHT
        //   x-----------------x-----------------x----------------x----------------x
        //   |                 |                 |                |                |
        //   |                 |                 |                |                |
        //   |                 |                 |                |                |
        //   x-----------------x-----------------x----------------x----------------x
        // BOTTOM-LEFT BOTTOM-LEFT-CENTER  BOTTOM-CENTER  BOTTOM-RIGHT-CENTER   BOTTOM-RIGHT
        */

        // UFO CENTER-FRONT
        // FRONT-LEFT-CENTER SQUARE
        // TOP-LEFT-CENTER
        -cornerX, sideY, cornerZ,
        // BOTTOM-CENTER
        center, -sideY, centerZ,
        // BOTTOM-LEFT-CENTER
        -cornerX, -sideY, cornerZ,


        // BOTTOM-CENTER
        center, -sideY, centerZ,
        // TOP-LEFT-CENTER
        -cornerX, sideY, cornerZ,
        // TOP-CENTER
        center, sideY, centerZ,


        // FRONT-RIGHT SQUARE
        // TOP-RIGHT
        sideX, sideY, center,
        // BOTTOM-RIGHT
        sideX, -sideY, center,
        // BOTTOM-RIGHT-CENTER
        cornerX, -sideY, cornerZ,


        // BOTTOM-RIGHT-CENTER
        cornerX, -sideY, cornerZ,
        // TOP-RIGHT-CENTER
        cornerX, sideY, cornerZ,
        // TOP-RIGHT
        sideX, sideY, center,


        // UFO CENTER-BACK
        // BACK-LEFT SQUARE
        // TOP-LEFT
        -sideX, sideY, center,
        // BOTTOM-LEFT
        -sideX, -sideY, center,
        // BOTTOM-LEFT-CENTER
        -cornerX, -sideY, -cornerZ,


        // BOTTOM-LEFT-CENTER
        -cornerX, -sideY, -cornerZ,
        // TOP-LEFT-CENTER
        -cornerX, sideY, -cornerZ,
        // TOP-LEFT
        -sideX, sideY, center,

        // BACK-RIGHT-CENTER SQUARE
        // TOP-CENTER
        center, sideY, -centerZ,
        // BOTTOM-CENTER
        center, -sideY, -centerZ,
        // BOTTOM-RIGHT-CENTER
        cornerX, -sideY, -cornerZ,

        // TOP-CENTER
        center, sideY, -centerZ,
        // BOTTOM-RIGHT-CENTER
        cornerX, -sideY, -cornerZ,
        // TOP-RIGHT-CENTER
        cornerX, sideY, -cornerZ,

        // DRAW TOP PART OF UFO
        //----------------------
        // CENTER
        center, centerY, center,
        // LEFT-BACK
        -cornerX, sideY, -cornerZ,
        // BACK
        center, sideY, -centerZ,

        // CENTER
        center, centerY, center,
        // LEFT-FRONT
        -cornerX, sideY, cornerZ,
        // LEFT
        -sideX, sideY, center,

        // CENTER
        center, centerY, center,
        // RIGHT-FRONT
        cornerX, sideY, cornerZ,
        // FRONT
        center, sideY, centerZ,

        // CENTER
        center, centerY, center,
        // RIGHT-BACK
        cornerX, sideY, -cornerZ,
        // RIGHT
        sideX, sideY, center,
    };

    GLfloat ufoLights[] = {
        // GRAPHICS FOR UFO FRONT LIGHT
        // TOP-LEFT-CENTER
        cornerLightX, sideY, cornerLightZ,
        // BOTTOM-LEFT-CENTER
        cornerLightX, -sideY, cornerLightZ,
        // BOTTOM-CENTER
        center, -sideY, lightDist,

        // BOTTOM-CENTER
        center, -sideY, lightDist,
        // TOP-CENTER
        center, sideY, lightDist,
        // TOP-LEFT-CENTER
        cornerLightX, sideY, cornerLightZ,

        // GRAPHICS FOR UFO BACK LIGHT
        // TOP-LEFT-CENTER
        cornerLightX, sideY, -cornerLightZ,
        // BOTTOM-CENTER
        center, -sideY, -lightDist,
        // BOTTOM-LEFT-CENTER
        cornerLightX, -sideY, -cornerLightZ,

        // BOTTOM-CENTER
        center, -sideY, -lightDist,
        // TOP-LEFT-CENTER
        cornerLightX, sideY, -cornerLightZ,
        // TOP-CENTER
        center, sideY, -lightDist
    };

    for (int i = 0; i < UFO_COLOR1_INDICES; i++) ufoColor1VertexData[i] = ufoColor1[i];

    for (int i = 0; i < UFO_COLOR2_INDICES; i++) ufoColor2VertexData[i] = ufoColor2[i];

    for (int i = 0; i < UFO_LIGHTS_INDICES; i++) ufoLightsVertexData[i] = ufoLights[i];

    verticesToNormals(UFO_COLOR1_INDICES, ufoColor1Data, ufoColor1NormalData);
    verticesToNormals(UFO_COLOR2_INDICES, ufoColor2Data, ufoColor2NormalData); 
    verticesToNormals(UFO_LIGHTS_INDICES, ufoLightsData, ufoLightsNormalData); 
}

/*! Initiates missile vertex, normal and light data.
 *
 * Missile vertex data is stored in \c GameWidget::missileVertexData array.
 * Normals are calculated to achieve light effect on game object. Normal is
 * calculated for each vertex and is stored in \c GameWidget::missileNormalData.
 *
 * Missile colours are defined to \c GameWidget::missileColourData. Red, green, blue and
 * alpha values are set. Values are form 0.0 to 1.0:
 * \code
 * colourData[0] = 1.0f; // red
 * colourData[1] = 0.2f; // green
 * colourData[2] = 0.2f; // blue
 * colourData[3] = 1.0f; // alpha
 * \endcode
 *
 * The material and light vectors are stored in \c GameWidget::missileLightsAmbientLmData 
 * (ambient light effect) and \c GameWidget::missileLightsDiffuseLmData (diffuse light effect). 
 *
 * The material and light vector is computed with GameWidget::GLes2MakeLightMaterialData with desired 
 * light effect vector and material colour data as arguments, e.g.:
 * \code
 * GLes2MakeLightMaterialData(lightAmbient, colourData, missileLightsAmbientLmData);
 * \endcode
 *
 * The vertex data is defined in an array of vertex points: x, y and z coordinates (three indices) for
 * each vertex. Some common measure variables and vertex points are defined first to simplify 
 * defining the actual object vertices:
 * \code
 * GLfloat scale = GameEngine::GameObjectRadiusMissile;
 * GLfloat rectWidth = scale * 0.3f;
 * GLfloat rectHeight = 4 * rectWidth;
 * ...
 * \endcode
 *
 * \code
            H0      
            /|\
           / | \
        T1/__|__\T2  
          |  |U3|    
          |  |  |    
          |  |  |    
          |  |  |    
          |  |  |    
          |  |  |    
          |  |  |    
          |  |  |    
          |  |  |    
          |__|__|    
         B1  U2 B2  
 * \endcode
 *
 * \code
 * GLfloat B1[] = {-rectWidth/2,-rectHeight/2, rectWidth/2};
 * GLfloat B2[] = { rectWidth/2,-rectHeight/2, rectWidth/2};
 * ...
 * \endcode
 *
 * \code
 * GLfloat vData[] = {
 *      U3[x], U3[y], U3[z],
 *      H0[x], H0[y], H0[z],
 *      T2[x], T2[y], T2[z],
 *      ...
 * };
 * \endcode
 *
 * To define more complex graphics objects you want to check out <a href="http://www.blender.org">Blender</a>!
 *
 * Finally vertice normals are calculated using \c GameWidget::verticesToNormals().
 *
 */
void GameWidget::initMissile()
{
    GLfloat *vertexData = missileVertexData;
    GLfloat *normalData = missileNormalData;
    GLfloat *colourData = missileColourData;

    colourData[0] = 1.0f;
    colourData[1] = 0.2f;
    colourData[2] = 0.2f;
    colourData[3] = 1.0f;

#ifdef SMASHMINER_CONFIG_USE_OPENGL_ES_2

    GLes2MakeLightMaterialData(lightAmbient, colourData, missileLightsAmbientLmData);
    GLes2MakeLightMaterialData(lightDiffuse, colourData, missileLightsDiffuseLmData);

#endif  // SMASHMINER_CONFIG_USE_OPENGL_ES_2

    /*
    //        H0      
    //        /|\
    //       / | \
    //    T1/__|__\T2  
    //      |  |U3|    
    //      |  |  |    
    //      |  |  |    
    //      |  |  |    
    //      |  |  |    
    //      |  |  |    
    //      |  |  |    
    //      |  |  |    
    //      |  |  |    
    //      |__|__|    
    //     B1  U2 B2  
    //
    */

    GLfloat scale = GameEngine::GameObjectRadiusMissile;
    GLfloat rectWidth = scale * 0.3f;
    GLfloat rectHeight = 4 * rectWidth;
    GLfloat headHeight = 2 * rectWidth;
    GLfloat wingWidth = rectWidth; 
    GLfloat wingHeight = rectHeight; 

    // Points
    GLfloat B1[] = {-rectWidth/2,-rectHeight/2, rectWidth/2};
    GLfloat B2[] = { rectWidth/2,-rectHeight/2, rectWidth/2};

    GLfloat T1[] = {-rectWidth/2 - rectWidth/4, rectHeight/2, rectWidth/2};
    GLfloat T2[] = { rectWidth/2 + rectWidth/4, rectHeight/2, rectWidth/2};

    GLfloat H0[] = { 0.0, rectHeight/2 + headHeight, 0.0 };

    GLfloat U2[] = { 0.0,-rectHeight/2, rectWidth/2};
    GLfloat U3[] = { 0.0, rectHeight/2, rectWidth/2 + rectWidth/3};

    /*
     * Tail:
     *             _._    C0   _._ 
     *              |    /|\    |
     *              |   / | \   |
     *              |  /  |  \  |
     *              | /   |   \ |
     *              |/    |    \|
     *              |_____C1____|
     *             /     / \     \
     *            /    -     -    \
     *           /   /         \   \
     *          /  -             -  \
     *         /_/                 \_\
     *
     *      W1                         W2
     */

    // center of missile body and starting point of the wings
    GLfloat C0[] = { 0.0, 0.0, 0.0 };
    GLfloat C1[] = { 0.0,-rectHeight/2, 0.0 };
    GLfloat W1[] = {-wingWidth, -wingHeight, 0.0 };
    GLfloat W2[] = { wingWidth, -wingHeight, 0.0 };

    GLfloat vData[] = {

        U3[x], U3[y], U3[z],
        H0[x], H0[y], H0[z],
        T2[x], T2[y], T2[z],

        U3[x], U3[y], U3[z],
        T2[x], T2[y], T2[z],
        B2[x], B2[y], B2[z],

        U3[x], U3[y], U3[z],
        B2[x], B2[y], B2[z],
        U2[x], U2[y], U2[z],
    
        U3[x], U3[y], U3[z],
        T1[x], T1[y], T1[z],
        H0[x], H0[y], H0[z],

        U3[x], U3[y], U3[z],
        U2[x], U2[y], U2[z],
        B1[x], B1[y], B1[z],

        U3[x], U3[y], U3[z],
        B1[x], B1[y], B1[z],
        T1[x], T1[y], T1[z],

        // - Wing 1 -

        C0[x], C0[y], C0[z],
        C1[x], C1[y], C1[z],
        W1[x], W1[y], W1[z],

        // - Wing 2 -

        C0[x], C0[y], C0[z],
        W2[x], W2[y], W2[z],
        C1[x], C1[y], C1[z]
    };

    for (int i = 0; i < MISSILE_INDICES; ++i)
        vertexData[i] = vData[i];

    verticesToNormals(MISSILE_INDICES, vertexData, normalData);  
}
